/*
 * Copyright By ZATI
 * Copyright By 3a3c88295d37870dfd3b25056092d1a9209824b256c341f2cdc296437f671617
 * All rights reserved.
 *
 * If you are not the intended user, you are hereby notified that any use, disclosure, copying, printing, forwarding or
 * dissemination of this property is strictly prohibited. If you have got this file in error, delete it from your system.
 */

package cn.wzc.crystal.security.controller;

import cn.hutool.extra.servlet.ServletUtil;
import cn.wzc.crystal.platform.golbal.GlobalErrorCode;
import cn.wzc.crystal.platform.golbal.GlobalException;
import cn.wzc.crystal.platform.support.ApiResult;
import cn.wzc.crystal.security.code.SecurityCode;
import cn.wzc.crystal.security.dto.LoginRequest;
import cn.wzc.crystal.security.helper.SecurityHelper;
import cn.wzc.crystal.security.service.AuthService;
import cn.wzc.crystal.security.vo.LoginInfo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.authentication.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

/**
 * 权限控制,负责:登录,登出,用户授权
 */
@Slf4j
@RestController
@RequiredArgsConstructor
public class AuthController {

	private final AuthService authService;
	private final AuthenticationManager authenticationManager;

	/**
	 * 用户登录
	 * 1. 首先调用登录认证器进行登录认证.
	 * 2. 登录之后调用授权处理服务类获取登录信息.
	 * 3. 组装登录信息之后赶回前端
	 *
	 * @param request 登录请求
	 * @return 登录结果, 带有当前登录用户信息
	 */
	@PostMapping("/login")
	@PreAuthorize("permitAll()")
	public ApiResult login(HttpServletRequest request, @RequestBody @Validated LoginRequest loginRequest) {
		Authentication currAuth = SecurityContextHolder.getContext().getAuthentication();
		if (currAuth instanceof UsernamePasswordAuthenticationToken) {
			return ApiResult.of(SecurityCode.USER_ALREADY_LOGIN);
		}
		try {
			final String username = loginRequest.getUsername();
			final String password = loginRequest.getPassword();
			final String clientIp = ServletUtil.getClientIP(request);

			final UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password);
			final UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) authenticationManager.authenticate(token);
			final LoginInfo loginInfo = authService.buildLoginInfo(username, clientIp);
			authentication.setDetails(loginInfo);
			SecurityContextHolder.getContext().setAuthentication(authentication);
			return ApiResult.of(GlobalErrorCode.SUCCESSFUL);
		} catch (DisabledException e) {
			return ApiResult.of(SecurityCode.USER_DISABLED);
		} catch (LockedException e) {
			return ApiResult.of(SecurityCode.USER_LOCKED);
		} catch (BadCredentialsException e) {
			return ApiResult.of(SecurityCode.BAD_CREDENTIALS);
		} catch (Exception e) {
			throw GlobalException.from(e);
		}
	}

	/**
	 * 用户登出
	 *
	 * @param request http 请求
	 * @return 登出结果
	 */
	@PostMapping("/logout")
	@PreAuthorize("permitAll()")
	public ApiResult logout(HttpServletRequest request) {
		HttpSession session = request.getSession(false);
		if (session != null) {
			session.invalidate();
		}
		SecurityContext context = SecurityContextHolder.getContext();
		context.setAuthentication(null);
		SecurityContextHolder.clearContext();
		return ApiResult.of(GlobalErrorCode.SUCCESSFUL);
	}

	/**
	 * 获取用户登录信息
	 *
	 * @return 当前登录信息
	 */
	@GetMapping("/loginInfo")
	@PreAuthorize("isAuthenticated()")
	public LoginInfo getLoginInfo() {
		return SecurityHelper.getLoginUserInfo();
	}


}
